目前我們已經會記帳、分類、畫圖了。下一步是讓「報表自動到手」,把理財養成習慣 — 我們今天做一個 每週消費摘要自動器:它會讀 expense.csv(找不到就自動建立示範)、產生「分類總額」的長條圖與 CSV 摘要,並嘗試把報告寄到你的 Email(若你提供環境變數憑證)。整個流程簡單、安全(鼓勵用環境變數),非常適合拿來展示「把資料流程自動化」的能力。
import os
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import smtplib, ssl
from email.message import EmailMessage
plt.rcParams['font.family'] = 'Heiti TC'
CSV_PATH = "expense.csv"
OUT_PNG = "weekly_category.png"
OUT_CSV = "weekly_summary.csv"
# 1) 若沒有 expense.csv,就建立示範資料
if not os.path.exists(CSV_PATH):
demo = pd.DataFrame({
"日期": ["2025-08-01","2025-08-02","2025-08-03","2025-08-06","2025-08-07","2025-08-08","2025-08-09"],
"類別": ["早餐","午餐","購物","交通","晚餐","咖啡","購物"],
"金額": [60,120,900,35,200,75,450]
})
demo.to_csv(CSV_PATH, index=False)
print("已建立示範 expense.csv")
# 2) 讀檔、轉型與取過去 7 天資料
df = pd.read_csv(CSV_PATH)
df['日期'] = pd.to_datetime(df['日期'], errors='coerce')
today = pd.Timestamp.now().normalize()
one_week_ago = today - pd.Timedelta(days=7)
recent = df[df['日期'] >= one_week_ago]
if recent.empty:
print("過去 7 天沒有資料,將以全部資料為基礎。")
recent = df.copy()
# 3) 分類加總並存檔
summary = recent.groupby('類別')['金額'].sum().sort_values(ascending=False)
summary_df = summary.reset_index().rename(columns={'金額':'總支出'})
summary_df.to_csv(OUT_CSV, index=False)
print(f"已輸出每週摘要:{OUT_CSV}")
# 4) 畫圖並存檔
plt.figure(figsize=(6,4))
summary.plot(kind='bar')
plt.title("過去 7 天各類別支出")
plt.xlabel("類別")
plt.ylabel("金額(元)")
plt.tight_layout()
plt.savefig(OUT_PNG)
plt.close()
print(f"已輸出圖檔:{OUT_PNG}")
# 5) 選擇性:把報表寄到 Email(若你不想寄,程式會跳過)
EMAIL_USER = os.getenv("REPORT_EMAIL_USER")
EMAIL_PASS = os.getenv("REPORT_EMAIL_PASS") # 建議使用 App Password,且不要硬寫在程式
if EMAIL_USER and EMAIL_PASS:
recipient = EMAIL_USER # 自寄檢查;可改成其他收件人
msg = EmailMessage()
msg["Subject"] = f"每週消費摘要 ({today.date()})"
msg["From"] = EMAIL_USER
msg["To"] = recipient
body = f"這是自動產生的每週消費摘要,請見附件({OUT_CSV}, {OUT_PNG})。"
msg.set_content(body)
# attach CSV
with open(OUT_CSV, "rb") as f:
msg.add_attachment(f.read(), maintype="text", subtype="csv", filename=OUT_CSV)
# attach image
with open(OUT_PNG, "rb") as f:
msg.add_attachment(f.read(), maintype="image", subtype="png", filename=OUT_PNG)
# 使用 Gmail SMTP 範例(必要時改成你的 SMTP)
try:
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(EMAIL_USER, EMAIL_PASS)
server.send_message(msg)
print("✅ 每週摘要已成功寄出(寄到自己的信箱)")
except Exception as e:
print("寄件失敗:", e)
print("你可以把檔案手動附上寄出,或檢查 SMTP 設定與帳密。")
else:
print("未設定郵件環境變數,已產生檔案,可手動寄出或設定後自動寄送。")